package nachos.threads;
import nachos.ag.BoatGrader;
import nachos.machine.Lib;
import nachos.machine.Machine;

public class Boat
{
    static BoatGrader bg;
    
    
    /****************************/
    static int oahu_child=0;
    static int oahu_adult=0;
    static int molokai_child=0;
    static int molokai_adult=0;
    static Condition2 child_oahu= null;
    static Condition2 child_molokai=null;
    static Condition2 adult_oahu=null;
    static Condition2 adult_molokai=null;
    static Condition2 boat = null;
    static Condition2 arrive = null;
  //  static Condition boating = null;
    /**
     * 第一把锁，利用条件变量的方式，控制两岸的等待队列
     * */
    static Lock  lock = null;
    /**
     * 第二把锁，控制两岸的人数
     * */
    static Lock lock2=null;
    /**
     * 第三把锁，控制船的启动
     * */
    static Lock lock3 = null;
    /**
     * 第四把锁，控制船的到达
     * */
    static Lock lock4 = null;

    static boolean finish=false;
    static int boat_position=0;
    static boolean first_ride=true;
    static void init_data()
    {
    	oahu_child = oahu_adult = molokai_child = molokai_adult =0;
    	lock = new Lock();
    	lock2 = new Lock();
    	lock3 = new Lock();
    	lock4 = new Lock();
    	child_oahu = new Condition2(lock);
    	child_molokai=new Condition2(lock);
    	adult_oahu=new Condition2(lock);
    	adult_molokai = new Condition2(lock);
    	boat =new Condition2(lock3);
    	//boating = new Condition(lock);
    	arrive = new Condition2(lock4);
    	boat_position = 0;
    	first_ride = true;
    }
    static void wake_boat()
    {
    //	System.out.println("w bo");
    //	KThread.currentThread().yield();
    	lock3.acquire();
    	boat.wake();
    	lock3.release();
    }
    static void sleep_boat()
    {
    	lock3.acquire();
    	boat.sleep();
    	lock3.release();
    }
    static void wake_arrive()
    {
    	lock4.acquire();
    	arrive.wake();
    	lock4.release();
    }
    static void sleep_arrive()
    {
    	lock4.acquire();
    	arrive.sleep();
    	lock4.release();
    }
    static boolean finish()
    {

    	try
    	{
    		lock2.acquire();
    		return oahu_child==0&&oahu_adult==0;
    	}finally
    	{
    		lock2.release();
    	}
    }
    /**
     * 船员类
     * */
    public static class  Person implements Runnable
    {
    	char type;
    	int position=0;
    	/**
    	 * 构造方法，传入一个值，表示是大人还是小孩
    	 * */
    	Person(char _type)
    	{
    		type = _type;
    	}
    	public void yield()
    	{
    		boolean modi=true;
    		if(modi)KThread.currentThread().yield();
    	}
    	/**
    	 * <p>根据船的位置不同和船员的类型不同，将线程加入不同的等待队列。
    	 * <p>
    	 * 等待完成时：
    	 * <ol>
    	 * <li>上船
    	 * <li>等待船到达
    	 * <li>上岸
    	 * <li>人数变动（锁控制）
    	 * <li>唤醒船，让船继续启动
    	 * </ol>
    	 * */
		@Override
		public void run() {
			while(!finish)
			{
				if(position==0)
				{
					if(type=='c')
					{
					//	System.out.println(1);
						lock.acquire();
						child_oahu.sleep();
						//boat.sleep();
						lock.release();
					//	System.out.println(2);
						if(!finish())
						{	
							//System.out.println(1);
							bg.ChildRowToMolokai();
							position=1;
						//	System.out.println(11);
							sleep_boat();
				//			System.out.println(12);
							bg.ChildRideToMolokai();
							lock2.acquire();
							oahu_child--;
							molokai_child++;
							lock2.release();
						//	System.out.println(2);
							//wake_arrive();
						}
					}
					else if(type=='a')
					{
						lock.acquire();
						adult_oahu.sleep();
						//boat.sleep();
						lock.release();
						if(!finish())
						{	
							bg.AdultRowToMolokai();

							sleep_boat();
							position=1;
							bg.AdultRideToMolokai();
							lock2.acquire();
							oahu_adult--;
							molokai_adult++;
							lock2.release();			
							//wake_arrive();
						}
					}
					
				}
				else if(position==1)
				{
					if(type=='c')
					{
						lock.acquire();
						child_molokai.sleep();
						//boat.sleep();
						lock.release();
						if(!finish())
						{	
							bg.ChildRowToOahu();
							sleep_boat();
							position=0;
							bg.ChildRideToOahu();
							lock2.acquire();
							molokai_child--;
							oahu_child++;
							lock2.release();	
							//wake_arrive();
						}
					}
					else if(type=='a')
					{
						lock.acquire();
						adult_molokai.sleep();
						//boat.sleep();
						lock.release();
						if(!finish())
						{	
							bg.AdultRowToOahu();
							sleep_boat();
							position=0;
							bg.AdultRideToOahu();
							lock2.acquire();
							molokai_adult--;
							oahu_adult++;
							lock2.release();		
							//wake_arrive();
						}
					}
				}
				//System.out.println('2');
				yield();
				wake_arrive();
			}

		}
    	
    }
    
    /****************************/
    
    
    public static void selfTest()
    {
	BoatGrader b = new BoatGrader();
	
	System.out.println("\n ***Testing Boats with only 2 children***");
	begin(0, 2, b);

//	System.out.println("\n ***Testing Boats with 2 children, 1 adult***");
//  	begin(1, 2, b);

//  	System.out.println("\n ***Testing Boats with 3 children, 3 adults***");
//  	begin(3, 3, b);
    }
    /**
     * 船控制类
     * */
    public static class B implements Runnable
    {
/**
 * <p>
 * 通过分析2个孩子1个大人时如何尽快把这个大人运过去，得到4个状态，进而分情况讨论：
 * <p>
 * 船在起点时：
 * <ul>
 * <li>终点有孩子：优先考虑成人过去（因为孩子可以把船开回来，使得这次运输‘有效果’）
 * <li>终点没有孩子：优先考虑小孩过去（2个孩子过去可以一个孩子把船开回来）
 * <li>起点只有1个小孩或成人：直接过去（最简单的情况）
 * <li>起点和终点都没有孩子：1个成人，成人过去；多个成人，游戏异常
 * </ul>
 * 船在终点时：
 * <ul>
 * <li>起点没有人，游戏结束
 * <li>起点有人且终点有孩子：1个孩子回去
 * <li>起点有人且终点没孩子：起点孩子数大于1:1个成人回去
 * <li>起点有人且终点没孩子：起点孩子数小于等于1：游戏异常
 * </ul>
 * */
		@Override
		public void run() {
			boolean modi=true;
			
			while(!finish())
			{
				int count = 0;
				//船在起点时
				if(boat_position==0)
				{
					//起点有人终点没孩子，孩子过去
					if(molokai_child==0&&oahu_child!=0)
					{
						//first_ride=false;
						if(oahu_child>=2)
						{
							yield();
							lock.acquire();
						//	System.out.println("wake ");
							child_oahu.wake();
							lock.release();
							yield();
							lock.acquire();
							child_oahu.wake();
							lock.release();

						//	System.out.println("wake ");
							count=2;
						//sleep_arrive();
						//sleep_arrive();
//							lock3.acquire();
//							boat.wakeAll();
//							boat_position=1;
//							lock3.release();
						}
						else if(oahu_child==1&&oahu_adult==0)
						{
							yield();
							lock.acquire();
							child_oahu.wake();
							//boat.wakeAll();
							//boat_position=1;
							lock.release();
							count=1;
//							lock3.acquire();
//							boat.wakeAll();
//							boat_position=1;
//							lock3.release();
							//sleep_arrive();
						}
						else
						{
							Lib.assertNotReached("only 1 child but it has too many adults failed~ ");
						}
					}
					//起点有人终点有孩子：成人优先过去
					else if(molokai_child!=0)
					{
							if(oahu_adult!=0)
							{
								yield();
								lock.acquire();
								adult_oahu.wake();
							//	boat.wakeAll();
							//	boat_position=1;
								lock.release();
								count=1;
								//sleep_arrive();
//								lock3.acquire();
//								boat.wakeAll();
//								boat_position=1;
//								lock3.release();
							}else if(oahu_child!=0)
							{
								

								int max = oahu_child>1?2:1;
								for(int k=0;k<max;k++)
								{
									yield();
									lock.acquire();
									child_oahu.wake();
									lock.release();
								}
								count=max;
						//		boat.wakeAll();
						//		boat_position=1;
								
							//sleep_arrive();
//								lock3.acquire();
//								boat.wakeAll();
//								boat_position=1;
//								lock3.release();
							}
					}
					//起点终点都没有孩子：1个成人，成人过去，多个成人，游戏结束
					else if(molokai_child==0&&oahu_child==0)
					{
						if(oahu_adult<2&&oahu_adult>0)
						{
							yield();
							lock.acquire();
							adult_oahu.wake();
						//	boat.wakeAll();
						//	boat_position=1;
							
							lock.release();
							count=1;
						//	sleep_arrive();
						}
						else
						{
							Lib.assertNotReached(" to many adult!");
						}

					}
					//KThread.currentThread().yield();
					for(int i=0;i<count;i++){
						yield();
						wake_boat();
					}
					boat_position=1;

				}
				//船在终点时
				else if(boat_position==1)
				{
					//终点有孩子，孩子回去
					if(molokai_child>0)
					{
						yield();
						lock.acquire();
						child_molokai.wake();
						count=1;
					//	boat.wakeAll();
					//	boat_position=0;
						lock.release();
						//sleep_arrive();
					}
					else 
					{
						//终点没孩子且起点孩子数大于1:1个成人回去
						if(oahu_child>1)
						{
							yield();
							lock.acquire();
							adult_molokai.wake();
				//			boat.wakeAll();
				//			boat_position=0;
							lock.release();
							count=1;
							//sleep_arrive();
						}else
						{	//终点没孩子且起点孩子数小于等于1：
							Lib.assertNotReached("molokai has no children and oahu has less than 1 child but boat in molokai ");
						}
					}
					//KThread.currentThread().yield();
					for(int i=0;i<count;i++){
						yield();
						wake_boat();
					}
					boat_position=0;

				}
				
				for(int i = 0;i<count;i++)
				{
					sleep_arrive();
				}
				}
			
		}
    	public void yield()
    	{
    		boolean modi=true;
    		if(modi)KThread.currentThread().yield();
    	}
    }
    public static void begin( int adults, int children, BoatGrader b )
    {
	// Store the externally generated autograder in a class
	// variable to be accessible by children.
	bg = b;

	init_data();
	oahu_adult=adults;
	oahu_child=children;
	for(int i=0;i<oahu_adult;i++)
	{
		AdultItinerary();
	}
	for(int i=0;i<oahu_child;i++)
	{
		 ChildItinerary();
	}
	KThread k = new KThread(new B());
	k.fork();
	k.join();
//	System.out.println("init data "+finish());

	}
	// Instantiate global variables here
	
	// Create threads here. See section 3.4 of the Nachos for Java
	// Walkthrough linked from the projects page.
/*
	Runnable r = new Runnable() {
	    public void run() {
                SampleItinerary();
            }
        };
        KThread t = new KThread(r);
        t.setName("Sample Boat Thread");
        t.fork();
*/
    //}

    static void AdultItinerary()
    {
    	Runnable runner = new Person('a');
    	new KThread(runner).fork();
	/* This is where you should put your solutions. Make calls
	   to the BoatGrader to show that it is synchronized. For
	   example:
	       bg.AdultRowToMolokai();
	   indicates that an adult has rowed the boat across to Molokai
	*/
    }

    static void ChildItinerary()
    {
    	Runnable runner = new Person('c');
    	new KThread(runner).fork();
    }

    static void SampleItinerary()
    {
	// Please note that this isn't a valid solution (you can't fit
	// all of them on the boat). Please also note that you may not
	// have a single thread calculate a solution and then just play
	// it back at the autograder -- you will be caught.
	System.out.println("\n ***Everyone piles on the boat and goes to Molokai***");
	bg.AdultRowToMolokai();
	bg.ChildRideToMolokai();
	bg.AdultRideToMolokai();
	bg.ChildRideToMolokai();
    }
    
}
